﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace CLFramework.Caching
{
    public static class CacheManager
    {
        private static object syncObj = new object();
        private static Hashtable ht = new Hashtable();
        private const int defaultCacheEntityDuration = 180;
        private const int defaultMaxEntityCount = 1000;
        private static Guid source;

        static CacheManager()
        {
            source = Guid.NewGuid();
        }

        /// <summary>
        /// This property is used to mark the source where the cache timestamp is updated from.
        /// </summary>
        public static Guid Source
        {
            get
            {
                return source;
            }
        }

        public static CacheEntityTable<TKey, TValue>
            GetCacheEntityTable<TKey, TValue>(string cacheKey)
        {
            return GetCacheEntityTable<TKey, TValue>(cacheKey, defaultCacheEntityDuration, defaultMaxEntityCount);
        }

        public static CacheEntityTable<TKey, TValue> 
            GetCacheEntityTable<TKey, TValue>(string cacheKey, int cacheEntityDuration, int maxEntityCount)
        {
            CacheEntityTable<TKey, TValue> table = null;
            lock (syncObj)
            {
                if (!ht.ContainsKey(cacheKey))
                {
                    table = new CacheEntityTable<TKey, TValue>(cacheKey);
                    table.CacheEntityDuration = cacheEntityDuration;
                    table.MaxEntityCount = maxEntityCount;
                    ht[cacheKey] = table;
                }
                else
                {
                    table = ht[cacheKey] as CacheEntityTable<TKey, TValue>;
                }
            }

            return table;
        }

        public static void Clean()
        {
            ArrayList keys;
            lock (syncObj)
            {
                keys = new ArrayList(ht.Keys);
            }
            foreach (object key in keys)
            {
                ICachedTable table = ht[key] as ICachedTable;
                if (table != null)
                    table.RemoveExpiredEntities();
            }
        }

        public static void RemoveAll()
        {
            ArrayList keys;
            lock (syncObj)
            {
                keys = new ArrayList(ht.Keys);
            }
            foreach (object key in keys)
            {
                ICachedTable table = ht[key] as ICachedTable;
                if (table != null)
                    table.RemoveAll();
            }
        }

        public static void RemoveAll(string cachekey)
        {
            ICachedTable table = ht[cachekey] as ICachedTable;
            if (table != null)
                table.RemoveAll();
        }

        public static List<CachedTableDisplay> GetAllCacheEntityTables()
        {
            List<CachedTableDisplay> result = new List<CachedTableDisplay>();
            foreach (object vl in ht.Values)
            {
                ICachedTable table = vl as ICachedTable;
                if (table != null)
                {
                    result.Add(new CachedTableDisplay()
                    {
                        CacheKey = table.CacheKey,
                        CacheType = table.CacheType,
                        MaxEntityCount = table.MaxEntityCount,
                        CacheEntityDuration = table.CacheEntityDuration,
                        KeysCount = table.KeysCount,
                    });
                }
            }

            return result;
        }
    }

    public class CachedTableDisplay
    {
        public string CacheKey { get; set; }

        public string CacheType { get; set; }

        public int KeysCount { get; set; }

        public int CacheEntityDuration { get; set; }

        public int MaxEntityCount { get; set; }
    }
}
